using EFCoreEnterpriseDemo.Data;
using EFCoreEnterpriseDemo.Models;
using Microsoft.EntityFrameworkCore;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Channels;
using System.Threading.Tasks;

namespace EFCoreEnterpriseDemo.Services
{
    public class OptimizedAuditService : IAuditService
    {
        private readonly IDbContextFactory<ApplicationDbContext> _contextFactory;
        private readonly Channel<AuditLog> _auditChannel = Channel.CreateUnbounded<AuditLog>();

        public OptimizedAuditService(IDbContextFactory<ApplicationDbContext> contextFactory)
        {
            _contextFactory = contextFactory;
            _ = ProcessAuditLogsAsync();
        }

        public async Task SaveAuditLogsAsync(List<AuditEntry> entries)
        {
            var logs = entries.Select(e => new AuditLog
            {
                TableName = e.TableName,
                Action = e.Action,
                RecordId = e.RecordId,
                OldValues = e.OldValues,
                NewValues = e.NewValues,
                ChangedColumns = e.ChangedColumns,
                UserId = e.UserId,
                UserName = e.UserName,
                IpAddress = e.IpAddress,
                UserAgent = e.UserAgent,
                CreatedAt = System.DateTime.UtcNow
            });

            foreach (var log in logs)
                await _auditChannel.Writer.WriteAsync(log);
        }

        private async Task ProcessAuditLogsAsync()
        {
            var batch = new List<AuditLog>();
            var batchSize = 100;
            var delay = System.TimeSpan.FromSeconds(5);

            while (true)
            {
                try
                {
                    using var timeout = new System.Threading.CancellationTokenSource(delay);
                    while (batch.Count < batchSize && await _auditChannel.Reader.WaitToReadAsync())
                    {
                        if (_auditChannel.Reader.TryRead(out var log))
                        {
                            batch.Add(log);
                        }
                    }

                    if (batch.Any())
                    {
                        await SaveBatchAsync(batch);
                        batch.Clear();
                    }
                }
                catch (System.Exception ex)
                {
                    // 记录错误日志
                    System.Console.WriteLine($"Audit processing error: {ex.Message}");
                }
            }
        }

        private async Task SaveBatchAsync(List<AuditLog> logs)
        {
            using var context = _contextFactory.CreateDbContext();
            await context.AuditLogs.AddRangeAsync(logs);
            await context.SaveChangesAsync();
        }
    }
}